﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.IO;

using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Rendering;

namespace ArusTextEditor
{
    public partial class TextEditor : UserControl
    {
        public TextEditor()
        {
            InitializeComponent();

            gtWidth = GridColTools.Width.Value;
            GridColTools.Width = new GridLength(0);

            FoldingManager foldingManager = FoldingManager.Install(txt.TextArea);
            XmlFoldingStrategy foldingStrategy = new XmlFoldingStrategy();
            foldingStrategy.UpdateFoldings(foldingManager, txt.Document);

            checkWordWrap.IsChecked = true;
            checkShowSpace.IsChecked = true;
            checkWordShowTab.IsChecked = true;
            checkShowNumLine.IsChecked = true;

            ApplyTextEditorOptions();

            wb.Visibility = System.Windows.Visibility.Hidden;
        }

        public string Text
        {
            get { return txt.Text; }
            set { txt.Text = value; }
        }
        public System.Windows.Visibility ShowToolBar
        {
            get { return buttonShowToolsPanel.Visibility; }
            set 
            {
                buttonShowToolsPanel.Visibility = value;
                buttonShowHelp.Visibility = value;
                buttonShowBrowser.Visibility = value;
                buttonNewForm.Visibility = value;
                buttonSaveFile.Visibility = value;
                buttonOpenFile.Visibility = value;

                if (value == System.Windows.Visibility.Visible)
                {
                    ToolPanel.Margin = new Thickness(0, 25, 5, 0);
                    Help.Margin = new Thickness(0, 25, 5, 0);
                    wb.Margin = new Thickness(0, 25, 5, 0);
                    txt.Margin = new Thickness(0, 25, 5, 0);
                }
                else
                {
                    ToolPanel.Margin = new Thickness(0, 0, 5, 0);
                    Help.Margin = new Thickness(0, 0, 5, 0);
                    wb.Margin = new Thickness(0, 0, 5, 0);
                    txt.Margin = new Thickness(0, 0, 5, 0);
                }
            }
        }
        public System.Windows.Visibility ShowStatusBar
        {
            get { return statusBar.Visibility; }
            set 
            { 
                statusBar.Visibility = value;
                if (value == System.Windows.Visibility.Visible)
                    gridMain.RowDefinitions[1].Height = new GridLength(0);
                else
                    gridMain.RowDefinitions[1].Height = new GridLength(20);
            }
        }
        public bool ShowNumLine
        {
            get { return (bool)checkShowNumLine.IsChecked; }
            set 
            {
                checkShowNumLine.IsChecked = value;
                ApplyTextEditorOptions();
            }
        }

        private void buttonPressed(object sender, RoutedEventArgs e)
        {
            Button b = (Button)sender;
            if (b.Tag == null) b.Tag = true;
            if ((bool)b.Tag)
            {
                b.Tag = false;
                b.Background = new SolidColorBrush(Color.FromRgb(90, 180, 230));
                b.BorderBrush = new SolidColorBrush(Color.FromRgb(70, 130, 180));
                b.Foreground = new SolidColorBrush(Color.FromRgb(255, 255, 255));
            }
            else
            {
                b.Tag = true;
                b.Background = null;
                b.BorderBrush = null;
                b.Foreground = new SolidColorBrush(Color.FromRgb(0, 0, 0));
            }
        }
        private double gtWidth;
        private void buttonShowToolsPanel_Click(object sender, RoutedEventArgs e)
        {
            buttonPressed(sender, e);
            if (!(bool)((sender as Button).Tag))
                GridColTools.Width = new GridLength(gtWidth);
            else
            {
                if (gtWidth < 30) gtWidth = 30;
                gtWidth = GridColTools.Width.Value;
                GridColTools.Width = new GridLength(0);
            }            
        }

        private void comboHighlightMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            switch ((comboHighlightMode.SelectedValue as ComboBoxItem).Content.ToString())
            {
                case "HTML": 
                    txt.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("HTML");
                    break;
                case "PHP":
                    txt.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("PHP");
                    break;
                case "XML":
                    txt.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("XML");
                    break;
            }
        }


        private void ApplyTextEditorOptions()
        {
            TextEditorOptions opt = new TextEditorOptions();
            opt.ShowEndOfLine = (bool)checkShowEndLine.IsChecked;
            opt.ShowSpaces = (bool)checkShowSpace.IsChecked;
            opt.ShowTabs = (bool)checkWordShowTab.IsChecked;
            txt.Options = opt;

            txt.WordWrap = (bool)checkWordWrap.IsChecked;
            txt.ShowLineNumbers = (bool)checkShowNumLine.IsChecked;
        }
        private void checkTextEditorOptions_Checked(object sender, RoutedEventArgs e)
        {
            ApplyTextEditorOptions();
        }

        private void InsertTag(string Tag)
        {
            int corSelStart = 0;
            switch (Tag)
            {
                case "P":
                    txt.SelectedText = "<p>" + txt.SelectedText + "</p>";
                    break;
                case "B":
                    txt.SelectedText = "<b>" + txt.SelectedText + "</b>";
                    break;
                case "TT":
                    txt.SelectedText = "<tt>" + txt.SelectedText + "</tt>";
                    break;
                case "I":
                    txt.SelectedText = "<i>" + txt.SelectedText + "</i>";
                    break;
                case "Strong":
                    txt.SelectedText = "<strong>" + txt.SelectedText + "</strong>";
                    break;
                case "Img":
                    txt.SelectedText = "<img src='" + txt.SelectedText + "' alt='" + textImgAlt.Text + "' />";
                    break;
                case "Img Left":
                    txt.SelectedText = "<img src='" + txt.SelectedText + "' style='float:left;' alt='" + textImgAlt.Text + "' />";
                    break;
                case "Img Rigth":
                    txt.SelectedText = "<img src='" + txt.SelectedText + "' style='float:right;' alt='" + textImgAlt.Text + "' />";
                    break;
                case "A":
                    txt.SelectedText = "<a href='" + txt.SelectedText + "' title='" + textATitle.Text + "' />";
                    break;
                case "Div":
                    txt.SelectedText = "<div>" + txt.SelectedText + "</div>";
                    break;
                case "Br":
                    txt.SelectedText = txt.SelectedText + "<br />";
                    break;
                case "Pre":
                    txt.SelectedText = "<pre>" + txt.SelectedText + "</pre>";
                    break;

                case "{}":
                    txt.SelectedText = "{" + txt.SelectedText + "|}";
                    corSelStart = -1;
                    break;
                case "[]":
                    txt.SelectedText = "[" + txt.SelectedText + "|]";
                    corSelStart = -1;                   
                    break;
                case "[#]":
                    txt.SelectedText = "[# ,|1|" + txt.SelectedText + "|#]";
                    corSelStart = -2;
                    break;
                case "|":
                    txt.SelectedText = txt.SelectedText + "|";
                    break;
            }
            int sl = txt.SelectionLength;
            txt.SelectionLength = 0;
            txt.SelectionStart = txt.SelectionStart + sl + corSelStart;
            txt.Focus();
        }

        private void  ButtonInsert_Click(object sender, RoutedEventArgs e)
        {
            InsertTag((sender as Button).Content.ToString());
        }

        private void buttonShowBrowser_Click(object sender, RoutedEventArgs e)
        {
            // TODO: использовать режим редактирования HTML у WebBrowser'а
            buttonPressed(sender, e);
            if (!(bool)((sender as Button).Tag))
            {
                if (txt.Text != "") wb.NavigateToString("<head><meta http-equiv='Content-Type' content='text/html;charset=UTF-8'></head>" + txt.Text);
                wb.Visibility = System.Windows.Visibility.Visible;
            }
            else wb.Visibility = System.Windows.Visibility.Hidden;            
        }

        private void txt_TextChanged(object sender, EventArgs e)
        {
            StatusTextLeft.Text = "Lines: " + txt.LineCount + " Length: " + txt.Document.TextLength;
        }

        private void buttonNewForm_Click(object sender, RoutedEventArgs e)
        {
            string Text = txt.Text;
            if (NewWindow("Редактирование", ref Text)) txt.Text = Text;
        }
        static public bool NewWindow(string Caption,ref string Text)
        {
            Window frm = new Window();
            frm.Title = Caption;
            frm.Width = 600; frm.Height = 500;
            frm.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            frm.WindowStyle = WindowStyle.ToolWindow;
            frm.Tag = false;
            frm.SizeChanged += new SizeChangedEventHandler(frm_SizeChanged);
            StackPanel sp = new StackPanel();
            frm.Content = sp;
            TextEditor txtChild = new TextEditor();
            txtChild.Text = Text;
            txtChild.Height = double.NaN;
            txtChild.Width = double.NaN;
            sp.Children.Add(txtChild);
            Button buttonOk = new Button();
            buttonOk.Content = "Ok";
            buttonOk.Tag = frm;
            buttonOk.Click += new RoutedEventHandler(buttonOk_Click);
            Button buttonCancel = new Button();
            buttonCancel.Content = "Cancel";
            buttonCancel.Tag = frm;
            buttonCancel.Click += new RoutedEventHandler(buttonCancel_Click);
            sp.Children.Add(buttonOk);
            sp.Children.Add(buttonCancel);

            frm.ShowInTaskbar = false;
            frm.ShowDialog();
            if ((bool)frm.Tag == true)
            {
                Text = txtChild.Text;
                return true;
            }
            else return false;
        }
        static void frm_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Window w = (sender as Window);
            if (w.Height > 70)
                ((w.Content as StackPanel).Children[0] as TextEditor).Height = w.Height - 70;
        }
        static void buttonOk_Click(object sender, RoutedEventArgs e)
        {
            Window w = ((sender as Button).Tag as Window);
            w.Tag = true;
            w.Close();
        }
        static void buttonCancel_Click(object sender, RoutedEventArgs e)
        {
            Window w = ((sender as Button).Tag as Window);
            w.Tag = false;
            w.Close();
        }

        private void buttonSaveFile_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.SaveFileDialog ofd = new Microsoft.Win32.SaveFileDialog();
            ofd.DefaultExt = ".txt";
            ofd.Filter = "Text documents (.txt)|*.txt";
            Nullable<bool> result = ofd.ShowDialog();
            if (result == true) File.WriteAllText(ofd.FileName, txt.Text);
        }

        private void buttonOpenFile_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
            ofd.DefaultExt = ".txt";
            ofd.Filter = "Text documents (.txt)|*.txt";
            Nullable<bool> result = ofd.ShowDialog();
            if (result == true) txt.Text = File.ReadAllText(ofd.FileName);
        }

        private void buttonShowHelp_Click(object sender, RoutedEventArgs e)
        {
            buttonPressed(sender, e);
            if (!(bool)((sender as Button).Tag)) Help.Visibility = System.Windows.Visibility.Visible;
            else Help.Visibility = System.Windows.Visibility.Hidden;            
        }

        private void buttonClearHTMLSpecChar_Click(object sender, RoutedEventArgs e)
        {
            txt.SelectedText = System.Web.HttpUtility.HtmlEncode(txt.SelectedText);
        }

        private void txt_KeyUp(object sender, KeyEventArgs e)
        {            
            switch (e.Key)
            {
                case Key.F1: InsertTag("P"); break;
                case Key.F2: InsertTag("Strong"); break;
                case Key.F3: InsertTag("Br"); break;
                case Key.F4: InsertTag("B"); break;
                case Key.F5: InsertTag("A"); break;
                case Key.F6: InsertTag("Img"); break;
                case Key.F7: InsertTag("[]"); break;
                case Key.F8: InsertTag("{}"); break;
                case Key.F9: InsertTag("|"); break;
                case Key.F11: InsertTag("[#]"); break;
            }
        }
    }

}
